package top.codedance.iotp.converter.service.master;

import top.codedance.iotp.converter.ConverterApplication;
import top.codedance.iotp.converter.bean.MasterConnectParam;
import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;
import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;
import com.intelligt.modbus.jlibmodbus.msg.request.ReadHoldingRegistersRequest;
import com.intelligt.modbus.jlibmodbus.msg.response.ReadHoldingRegistersResponse;
import com.intelligt.modbus.jlibmodbus.serial.SerialParameters;
import com.intelligt.modbus.jlibmodbus.serial.SerialPort;
import com.intelligt.modbus.jlibmodbus.serial.SerialPortFactoryPJC;
import com.intelligt.modbus.jlibmodbus.serial.SerialUtils;
import org.apache.log4j.Logger;

public class RtuMaster extends AdapterModbusMaster {
    private Logger logger = ConverterApplication.getLogger(RtuMaster.class);
    private ModbusMaster master = null;

    public RtuMaster(MasterConnectParam mcp) {
        super(mcp);
    }

    @Override
    public void init() {
        try {
            connect();
        } catch (Exception ex) {
            logger.info(ex.getMessage());
            System.exit(0);
        }
        long time = System.currentTimeMillis();
        while (true) {
            if (!master.isConnected()) {
                try {
                    connect();
                } catch (Exception ex) {
                    logger.info(ex.getMessage());
                }
                logger.info("Master is reconnect!");
            } else {
                if (System.currentTimeMillis() - time > 1000 * 3600 * 2) {
                    destory();
                    try {
                        connect();
                    } catch (Exception ex) {
                        logger.info(ex.getMessage());
                    }
                    time = System.currentTimeMillis();
                }
            }
            try {
                Thread.sleep(3000);
            } catch (Exception ex) {
            }
        }
    }

    @Override
    public void connect() {
        try {
            SerialParameters sp = new SerialParameters();
            sp.setDevice(param.getComName());
            sp.setBaudRate(SerialPort.BaudRate.getBaudRate(param.getBaudRate()));
            sp.setDataBits(param.getDataBits());
            sp.setStopBits(param.getStopBits());
            sp.setParity(SerialPort.Parity.getParity(param.getParity()));
            SerialUtils.setSerialPortFactory(new SerialPortFactoryPJC());
            master = ModbusMasterFactory.createModbusMasterRTU(sp);
            master.connect();
            logger.info("Rtu master is running!");
        } catch (Exception e) {
            logger.debug(e.getMessage());
        }
    }

    @Override
    public boolean isOpen() {
        return master.isConnected();
    }

    @Override
    public void destory() {
        if (master != null) {
            try {
                master.disconnect();
            } catch (Exception e) {
            }
            master = null;
        }
    }

    @Override
    public int readHoldingRegister(int offset) {
        int result;
        int[] ints = readHoldingRegisterRange(offset, 1);
        if (ints.length > 0) {
            result = ints[0];
        } else {
            result = 0;
        }
        return result;
    }

    @Override
    public int[] readHoldingRegisterRange(int offset, int quantity) {
        int[] result;
        try {
            result = master.readHoldingRegisters(param.getId(), offset, quantity);
        } catch (Exception e) {
            result = null;
        }
        return result;
    }

    @Override
    public void writeHoldingRegister(int offset, int value) {
        try {
            master.writeSingleRegister(param.getId(), offset, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void writeHoldingRegisterRange(int offset, int[] range) {
        if (range.length > 0) {
            try {
                master.writeMultipleRegisters(param.getId(), offset, range);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean[] readCoilRange(int offset, int quantity) {
        boolean[] result;
        try {
            result = master.readCoils(param.getId(), offset, quantity);
        } catch (Exception e) {
            result = null;
        }
        return result;
    }

    @Override
    public void writeCoil(int offset, boolean value) {
        try {
            master.writeSingleCoil(param.getId(), offset, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void writeCoilRange(int offset, boolean[] range) {
        if (range.length > 0) {
            try {
                master.writeMultipleCoils(param.getId(), offset, range);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public byte[] request(int offset, int quantity) {
        byte[] result;
        try {
            ReadHoldingRegistersRequest readRequest = new ReadHoldingRegistersRequest();
            readRequest.setServerAddress(param.getId());
            readRequest.setStartAddress(offset);
            readRequest.setQuantity(quantity);
            master.processRequest(readRequest);
            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) readRequest.getResponse();
            result = response.getBytes();
        } catch (Exception e) {
            result = new byte[0];
            logger.debug(e.getMessage());
        }
        return result;
    }
}
